diff --git a/assets/src/bundles/webapp/webapp.css b/assets/src/bundles/webapp/webapp.css
index 56b76704..61a85948 100644
--- a/assets/src/bundles/webapp/webapp.css
+++ b/assets/src/bundles/webapp/webapp.css
@@ -1,776 +1,783 @@
 /**
  * Copyright (C) 2018-2022  The Software Heritage developers
  * See the AUTHORS file at the top-level directory of this distribution
  * License: GNU Affero General Public License version 3, or any later version
  * See top-level LICENSE file for more information
  */
 
 html {
     height: 100%;
     overflow-x: hidden;
     scroll-behavior: auto !important;
 }
 
 body {
     min-height: 100%;
     margin: 0;
     position: relative;
     padding-bottom: 120px;
 }
 
 /* The Alegreya font used in swh-web ships some ligatures producing
 confusing text rendering, for instance the ligatures for `~` and some
 characters like e, y, u, ... so disable font common ligatures */
 * {
     font-variant-ligatures: no-common-ligatures;
 }
 
 a:active,
 a.active {
     outline: none;
 }
 
 code {
     background-color: #f9f2f4;
 }
 
 pre code {
     background-color: transparent;
 }
 
 footer {
     background-color: #262626;
     color: #fff;
     font-size: 0.8rem;
     position: absolute;
     bottom: 0;
     width: 100%;
     padding-top: 10px;
     padding-bottom: 10px;
 }
 
 footer a,
 footer a:visited,
 footer a:hover {
     color: #fecd1b;
 }
 
 footer a:hover {
     text-decoration: underline;
 }
 
 .link-color {
     color: #fecd1b;
 }
 
 pre {
     background-color: #f5f5f5;
     border: 1px solid #ccc;
     border-radius: 4px;
     padding: 9.5px;
     font-size: 0.8rem;
 }
 
 .btn.active {
     background-color: #e7e7e7;
 }
 
 .card {
     margin-bottom: 5px !important;
     overflow-x: auto;
 }
 
 .navbar-brand {
     padding: 5px;
     margin-right: 0;
 }
 
 .table {
     margin-bottom: 0;
 }
 
 .swh-table thead {
     background-color: #f2f4f5;
     border-top: 1px solid rgb(0 0 0 / 20%);
     font-weight: normal;
 }
 
 .swh-table-striped th {
     border-top: none;
 }
 
 .swh-table-striped tbody tr:nth-child(even) {
     background-color: #f2f4f5;
 }
 
 .swh-table-striped tbody tr:nth-child(odd) {
     background-color: #fff;
 }
 
 .swh-web-app-link a {
     text-decoration: none;
     border: none;
 }
 
 .swh-web-app-link:hover {
     background-color: #efeff2;
 }
 
 .table > thead > tr > th {
     border-top: none;
     border-bottom: 1px solid #e20026;
 }
 
 .table > tbody > tr > td {
     border-style: none;
 }
 
 .sitename .first-word,
 .sitename .second-word {
     color: rgb(0 0 0 / 75%);
     font-weight: normal;
     font-size: 1.2rem;
 }
 
 .sitename .first-word {
     font-family: "Alegreya Sans", sans-serif;
 }
 
 .sitename .second-word {
     font-family: Alegreya, serif;
 }
 
 .swh-counter {
     font-size: 150%;
 }
 
 @media (max-width: 600px) {
     .swh-counter-container {
         margin-top: 1rem;
     }
 }
 
 .swh-http-error {
     margin: 0 auto;
     text-align: center;
 }
 
 .swh-http-error-head {
     color: #2d353c;
     font-size: 30px;
 }
 
 .swh-http-error-code {
     bottom: 60%;
     color: #2d353c;
     font-size: 96px;
     line-height: 80px;
     margin-bottom: 10px !important;
 }
 
 .swh-http-error-desc {
     font-size: 12px;
     color: #647788;
     text-align: center;
 }
 
 .swh-http-error-desc pre {
     display: inline-block;
     text-align: left;
     max-width: 800px;
     white-space: pre-wrap;
 }
 
 .swh-list-unstyled {
     list-style: none;
 }
 
 .popover {
     max-width: 97%;
     z-index: 40000;
 }
 
 .modal {
     text-align: center;
     padding: 0 !important;
     z-index: 50000;
 }
 
 .modal::before {
     content: "";
     display: inline-block;
     height: 100%;
     vertical-align: middle;
     margin-right: -4px;
 }
 
 .modal-dialog {
     display: inline-block;
     text-align: left;
     vertical-align: middle;
 }
 
 .dropdown-submenu {
     position: relative;
 }
 
 .dropdown-submenu .dropdown-menu {
     top: 0;
     left: -100%;
     margin-top: -5px;
     margin-left: -2px;
 }
 
 .dropdown-item:hover,
 .dropdown-item:focus {
     background-color: rgb(0 0 0 / 10%);
 }
 
 a.dropdown-left::before {
     content: "\f035e";
     font-family: "Material Design Icons";
     display: block;
     width: 20px;
     height: 20px;
     float: left;
     margin-left: 0;
 }
 
 #swh-navbar {
     border-style: solid;
     border-top-style: none;
     border-left-style: none;
     border-right-style: none;
     border-bottom-width: 5px;
     border-image:
         linear-gradient(
             to right,
             rgb(226 0 38) 0%,
             rgb(254 205 27) 100%
         )
         1 1 1 1;
     width: 100%;
     padding: 5px;
     margin-bottom: 10px;
     margin-top: 60px;
     justify-content: normal;
     flex-wrap: nowrap;
     height: 72px;
     overflow: hidden;
 }
 
 #back-to-top {
     display: none;
     position: fixed;
     bottom: 30px;
     right: 30px;
     z-index: 10;
 }
 
 #back-to-top a img {
     display: block;
     width: 32px;
     height: 32px;
     background-size: 32px 32px;
     text-indent: -999px;
     overflow: hidden;
 }
 
 .swh-top-bar {
     direction: ltr;
     height: 30px;
     position: fixed;
     top: 0;
     left: 0;
     width: 100%;
     z-index: 99999;
     background-color: #262626;
     color: #fff;
     text-align: center;
     font-size: 14px;
 }
 
 .swh-top-bar ul {
     margin-top: 4px;
     padding-left: 0;
     white-space: nowrap;
 }
 
 .swh-top-bar li {
     display: inline-block;
     margin-left: 10px;
     margin-right: 10px;
 }
 
 .swh-top-bar a,
 .swh-top-bar a:visited {
     color: white;
 }
 
 .swh-top-bar a.swh-current-site,
 .swh-top-bar a.swh-current-site:visited {
     color: #fecd1b;
 }
 
-.swh-banner-iframe {
+.swh-banner {
     height: 30px;
     position: fixed;
     top: 30px;
     left: 0;
     width: 100%;
     z-index: 99999;
     border: none;
 }
 
+.swh-banner .row {
+    height: 30px;
+    background-color: #fecd1b;
+    color: #e20026;
+    font-size: larger;
+}
+
 .swh-position-left {
     position: absolute;
     left: 0;
 }
 
 .swh-position-right {
     position: absolute;
     right: 0;
 }
 
 .swh-background-gray {
     background: #efeff2;
 }
 
 .swh-donate-link {
     border: 1px solid #fecd1b;
     background-color: #e20026;
     color: white !important;
     padding: 3px;
     border-radius: 3px;
 }
 
 .swh-navbar-content h4 {
     padding-top: 7px;
 }
 
 .swh-navbar-content .bread-crumbs {
     display: block;
     margin-left: -40px;
 }
 
 .swh-navbar-content .bread-crumbs li.bc-no-root {
     padding-top: 7px;
 }
 
 .main-sidebar {
     margin-top: 60px;
 }
 
 .sidebar {
     height: calc(100% - 7rem);
 }
 
 .content-wrapper {
     background: none;
 }
 
 .brand-image {
     max-height: 40px;
 }
 
 .brand-link {
     padding-top: 18.5px;
     padding-bottom: 18px;
     padding-left: 4px;
     border-bottom: 5px solid #e20026 !important;
 }
 
 .navbar-header a,
 ul.dropdown-menu a,
 ul.navbar-nav a,
 ul.nav-sidebar a {
     border-bottom-style: none;
     color: #323232;
 }
 
 .swh-sidebar .nav-link.active {
     color: #323232 !important;
     background-color: #e7e7e7 !important;
 }
 
 .nav-tabs .nav-link.active {
     border-top: 3px solid #e20026;
 }
 
 .swh-image-error {
     width: 80px;
     height: auto;
 }
 
 @media (max-width: 600px) {
     .card {
         min-width: 80%;
     }
 
     .swh-image-error {
         width: 40px;
         height: auto;
     }
 
     .swh-donate-link {
         display: none;
     }
 }
 
 .form-check-label {
     padding-top: 4px;
 }
 
 .swhid {
     white-space: pre-wrap;
 }
 
 .swhid .swhid-option {
     display: inline-block;
     margin-right: 5px;
     line-height: 1rem;
 }
 
 .nav-pills .nav-link:not(.active):hover {
     color: rgb(0 0 0 / 55%);
 }
 
 .swh-heading-color {
     color: #e20026 !important;
 }
 
 .sidebar-mini.sidebar-collapse .main-sidebar:hover {
     width: 4.6rem;
 }
 
 .sidebar-mini.sidebar-collapse .main-sidebar:hover .user-panel > .info,
 .sidebar-mini.sidebar-collapse .main-sidebar:hover .nav-sidebar .nav-link p,
 .sidebar-mini.sidebar-collapse .main-sidebar:hover .brand-text {
     visibility: hidden !important;
 }
 
 .sidebar .nav-link p,
 .main-sidebar .brand-text,
 .sidebar .user-panel .info {
     transition: none;
 }
 
 .sidebar-mini.sidebar-mini.sidebar-collapse .sidebar {
     padding-right: 0;
 }
 
 .swh-words-logo {
     position: absolute;
     top: 0;
     left: 0;
     width: 73px;
     height: 73px;
     text-align: center;
     font-size: 10pt;
     color: rgb(0 0 0 / 75%);
 }
 
 .swh-words-logo:hover {
     text-decoration: none;
 }
 
 .swh-words-logo-swh {
     line-height: 1;
     padding-top: 13px;
     visibility: hidden;
 }
 
 hr.swh-faded-line {
     border: 0;
     height: 1px;
     background-image: linear-gradient(to left, #f0f0f0, #8c8b8b, #f0f0f0);
 }
 
 /* Ensure that section title with link is colored like standard section title */
 .swh-readme h1 a,
 .swh-readme h2 a,
 .swh-readme h3 a,
 .swh-readme h4 a,
 .swh-readme h5 a,
 .swh-readme h6 a {
     color: #e20026;
 }
 
 /* Make list compact in reStructuredText rendering */
 .swh-rst li p {
     margin-bottom: 0;
 }
 
 .swh-readme-txt pre {
     background: none;
     border: none;
 }
 
 .swh-coverage {
     padding-top: 0.3rem;
     border: none;
     overflow: visible;
 }
 
 .swh-coverage a {
     text-decoration: none;
 }
 
 .swh-coverage-col {
     padding-left: 10px;
     padding-right: 10px;
 }
 
 .swh-coverage-header {
     padding-top: 0;
     padding-bottom: 0;
 }
 
 .swh-coverage-logo {
     display: block;
     width: 100%;
     height: 50px;
     margin-left: auto;
     margin-right: auto;
     object-fit: contain;
 
     /* polyfill for old browsers, see https://github.com/bfred-it/object-fit-images */
     font-family: "object-fit: contain;";
 }
 
 .swh-coverage-list {
     width: 100%;
     height: 320px;
     border: none;
 }
 
 .swh-coverage-chevron {
     position: absolute;
     right: 0;
 }
 
 .swh-coverage .card-header .mdi {
     transition: 0.3s transform ease-in-out;
 }
 
 .swh-coverage .card-header .collapsed .mdi {
     transform: rotate(90deg);
 }
 
 .swh-coverage-info-body {
     max-height: 150px;
     overflow-y: auto;
     overflow-x: hidden;
     scrollbar-width: thin; /* Firefox only */
     padding: 0;
 }
 
 /* Thin scrollbar for chromium based browsers */
 
 .swh-coverage-info-body::-webkit-scrollbar {
     width: 4px;
 }
 
 .swh-coverage-info-body::-webkit-scrollbar-track {
     background: #eff0f1;
 }
 
 .swh-coverage-info-body::-webkit-scrollbar-thumb {
     background: #909396;
 }
 
 tr.swh-tr-hover-highlight:hover td {
     background: #ededed;
 }
 
 tr.swh-api-doc-route a {
     text-decoration: none;
 }
 
 .swh-apidoc .col {
     margin: 10px;
 }
 
 .swh-apidoc .swh-rst blockquote {
     border: 0;
     margin: 0;
     padding: 0;
 }
 
 a.toggle-col {
     text-decoration: none;
 }
 
 a.toggle-col.col-hidden {
     text-decoration: line-through;
 }
 
 .admonition.warning {
     background: #fcf8e3;
     border: 1px solid #faebcc;
     padding: 15px;
     border-radius: 4px;
 }
 
 .admonition.warning p {
     margin-bottom: 0;
 }
 
 .admonition.warning .first {
     font-size: 1.5rem;
 }
 
 .swh-popover {
     max-height: 50vh;
     overflow-y: auto;
     overflow-x: auto;
     padding: 0;
 }
 
 @media screen and (min-width: 768px) {
     .swh-popover {
         max-width: 50vw;
     }
 }
 
 .swh-popover pre {
     white-space: pre-wrap;
     margin-bottom: 0;
 }
 
 .d3-wrapper {
     position: relative;
     height: 0;
     width: 100%;
     padding: 0;
 
     /* padding-bottom will be overwritten by JavaScript later */
     padding-bottom: 100%;
 }
 
 .d3-wrapper > svg {
     position: absolute;
     height: 100%;
     width: 100%;
     left: 0;
     top: 0;
 }
 
 div.d3-tooltip {
     position: absolute;
     text-align: center;
     width: auto;
     height: auto;
     padding: 2px;
     font: 12px sans-serif;
     background: white;
     border: 1px solid black;
     border-radius: 4px;
     pointer-events: none;
 }
 
 .page-link {
     cursor: pointer;
 }
 
 .wrapper {
     overflow: hidden;
 }
 
 .swh-badge {
     padding-bottom: 1rem;
     cursor: pointer;
 }
 
 .swh-badge-html,
 .swh-iframe-html,
 .swh-badge-md,
 .swh-badge-rst {
     white-space: pre-wrap !important;
 }
 
 /* Material Design icons alignment tweaks */
 
 .mdi {
     display: inline-block;
 }
 
 .mdi-camera {
     transform: translateY(1px);
 }
 
 .mdi-source-commit {
     transform: translateY(2px);
 }
 
 /* To set icons at a fixed width. Great to use when different
    icon widths throw off alignment. Courtesy of Font Awesome. */
 .mdi-fw {
     text-align: center;
     width: 1.25em;
 }
 
 .main-header .nav-link {
     height: inherit;
 }
 
 .nav-sidebar .nav-header:not(:first-of-type) {
     padding-top: 1rem;
 }
 
 .nav-sidebar .nav-link {
     padding-top: 0;
     padding-bottom: 0;
 }
 
 .nav-sidebar > .nav-item .nav-icon {
     vertical-align: sub;
 }
 
 .swh-search-icon {
     line-height: 1rem;
     vertical-align: middle;
 }
 
 .swh-search-navbar {
     position: absolute;
     top: 0.7rem;
     right: 15rem;
     z-index: 50000;
     width: 500px;
 }
 
 .sidebar-collapse .swh-search-navbar {
     right: 4rem;
 }
 
 .swh-corner-ribbon {
     width: 200px;
     background: #fecd1b;
     color: #e20026;
     position: absolute;
     text-align: center;
     letter-spacing: 1px;
     box-shadow: 0 0 3px rgb(0 0 0 / 30%);
     top: 85px;
     right: -50px;
     left: auto;
     transform: rotate(45deg);
     z-index: 2000;
 }
 
 @media screen and (max-width: 600px) {
     .swh-corner-ribbon {
         top: 53px;
         right: -65px;
     }
 }
 
 .invalid-feedback {
     font-size: 100%;
 }
 
 .swh-required-label::after {
     content: "*";
     color: #f00;
 }
diff --git a/swh/web/common/utils.py b/swh/web/common/utils.py
index 27345842..1fa2d4b6 100644
--- a/swh/web/common/utils.py
+++ b/swh/web/common/utils.py
@@ -1,519 +1,520 @@
 # Copyright (C) 2017-2022  The Software Heritage developers
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU Affero General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
 from datetime import datetime, timezone
 import functools
 import os
 import re
 from typing import Any, Callable, Dict, List, Mapping, Optional
 import urllib.parse
 
 from bs4 import BeautifulSoup
 from docutils.core import publish_parts
 import docutils.parsers.rst
 import docutils.utils
 from docutils.writers.html5_polyglot import HTMLTranslator, Writer
 from iso8601 import ParseError, parse_date
 from pkg_resources import get_distribution
 from prometheus_client.registry import CollectorRegistry
 import requests
 from requests.auth import HTTPBasicAuth
 
 from django.core.cache import cache
 from django.core.cache.backends.base import DEFAULT_TIMEOUT
 from django.http import HttpRequest, QueryDict
 from django.shortcuts import redirect
 from django.urls import resolve
 from django.urls import reverse as django_reverse
 
 from swh.web.auth.utils import (
     ADD_FORGE_MODERATOR_PERMISSION,
     ADMIN_LIST_DEPOSIT_PERMISSION,
     MAILMAP_ADMIN_PERMISSION,
 )
 from swh.web.common.exc import BadInputExc, sentry_capture_exception
 from swh.web.config import SWH_WEB_SERVER_NAME, get_config, search
 
 SWH_WEB_METRICS_REGISTRY = CollectorRegistry(auto_describe=True)
 
 SWHID_RE = "swh:1:[a-z]{3}:[0-9a-z]{40}"
 
 swh_object_icons = {
     "alias": "mdi mdi-star",
     "branch": "mdi mdi-source-branch",
     "branches": "mdi mdi-source-branch",
     "content": "mdi mdi-file-document",
     "cnt": "mdi mdi-file-document",
     "directory": "mdi mdi-folder",
     "dir": "mdi mdi-folder",
     "origin": "mdi mdi-source-repository",
     "ori": "mdi mdi-source-repository",
     "person": "mdi mdi-account",
     "revisions history": "mdi mdi-history",
     "release": "mdi mdi-tag",
     "rel": "mdi mdi-tag",
     "releases": "mdi mdi-tag",
     "revision": "mdi mdi-rotate-90 mdi-source-commit",
     "rev": "mdi mdi-rotate-90 mdi-source-commit",
     "snapshot": "mdi mdi-camera",
     "snp": "mdi mdi-camera",
     "visits": "mdi mdi-calendar-month",
 }
 
 
 def reverse(
     viewname: str,
     url_args: Optional[Dict[str, Any]] = None,
     query_params: Optional[Mapping[str, Optional[str]]] = None,
     current_app: Optional[str] = None,
     urlconf: Optional[str] = None,
     request: Optional[HttpRequest] = None,
 ) -> str:
     """An override of django reverse function supporting query parameters.
 
     Args:
         viewname: the name of the django view from which to compute a url
         url_args: dictionary of url arguments indexed by their names
         query_params: dictionary of query parameters to append to the
             reversed url
         current_app: the name of the django app tighten to the view
         urlconf: url configuration module
         request: build an absolute URI if provided
 
     Returns:
         str: the url of the requested view with processed arguments and
         query parameters
     """
 
     if url_args:
         url_args = {k: v for k, v in url_args.items() if v is not None}
 
     url = django_reverse(
         viewname, urlconf=urlconf, kwargs=url_args, current_app=current_app
     )
 
     params: Dict[str, str] = {}
     if query_params:
         params = {k: v for k, v in query_params.items() if v is not None}
 
     if params:
         query_dict = QueryDict("", mutable=True)
         query_dict.update(dict(sorted(params.items())))
         url += "?" + query_dict.urlencode(safe="/;:")
 
     if request is not None:
         url = request.build_absolute_uri(url)
 
     return url
 
 
 def datetime_to_utc(date):
     """Returns datetime in UTC without timezone info
 
     Args:
         date (datetime.datetime): input datetime with timezone info
 
     Returns:
         datetime.datetime: datetime in UTC without timezone info
     """
     if date.tzinfo and date.tzinfo != timezone.utc:
         return date.astimezone(tz=timezone.utc)
     else:
         return date
 
 
 def parse_iso8601_date_to_utc(iso_date: str) -> datetime:
     """Given an ISO 8601 datetime string, parse the result as UTC datetime.
 
     Returns:
         a timezone-aware datetime representing the parsed date
 
     Raises:
         swh.web.common.exc.BadInputExc: provided date does not respect ISO 8601 format
 
     Samples:
         - 2016-01-12
         - 2016-01-12T09:19:12+0100
         - 2007-01-14T20:34:22Z
 
     """
     try:
         date = parse_date(iso_date)
         return datetime_to_utc(date)
     except ParseError as e:
         raise BadInputExc(e)
 
 
 def shorten_path(path):
     """Shorten the given path: for each hash present, only return the first
     8 characters followed by an ellipsis"""
 
     sha256_re = r"([0-9a-f]{8})[0-9a-z]{56}"
     sha1_re = r"([0-9a-f]{8})[0-9a-f]{32}"
 
     ret = re.sub(sha256_re, r"\1...", path)
     return re.sub(sha1_re, r"\1...", ret)
 
 
 def format_utc_iso_date(iso_date, fmt="%d %B %Y, %H:%M:%S UTC"):
     """Turns a string representation of an ISO 8601 datetime string
     to UTC and format it into a more human readable one.
 
     For instance, from the following input
     string: '2017-05-04T13:27:13+02:00' the following one
     is returned: '04 May 2017, 11:27 UTC'.
     Custom format string may also be provided
     as parameter
 
     Args:
         iso_date (str): a string representation of an ISO 8601 date
         fmt (str): optional date formatting string
 
     Returns:
         str: a formatted string representation of the input iso date
     """
     if not iso_date:
         return iso_date
     date = parse_iso8601_date_to_utc(iso_date)
     return date.strftime(fmt)
 
 
 def gen_path_info(path):
     """Function to generate path data navigation for use
     with a breadcrumb in the swh web ui.
 
     For instance, from a path /folder1/folder2/folder3,
     it returns the following list::
 
         [{'name': 'folder1', 'path': 'folder1'},
          {'name': 'folder2', 'path': 'folder1/folder2'},
          {'name': 'folder3', 'path': 'folder1/folder2/folder3'}]
 
     Args:
         path: a filesystem path
 
     Returns:
         list: a list of path data for navigation as illustrated above.
 
     """
     path_info = []
     if path:
         sub_paths = path.strip("/").split("/")
         path_from_root = ""
         for p in sub_paths:
             path_from_root += "/" + p
             path_info.append({"name": p, "path": path_from_root.strip("/")})
     return path_info
 
 
 def parse_rst(text, report_level=2):
     """
     Parse a reStructuredText string with docutils.
 
     Args:
         text (str): string with reStructuredText markups in it
         report_level (int): level of docutils report messages to print
             (1 info 2 warning 3 error 4 severe 5 none)
 
     Returns:
         docutils.nodes.document: a parsed docutils document
     """
     parser = docutils.parsers.rst.Parser()
     components = (docutils.parsers.rst.Parser,)
     settings = docutils.frontend.OptionParser(
         components=components
     ).get_default_values()
     settings.report_level = report_level
     document = docutils.utils.new_document("rst-doc", settings=settings)
     parser.parse(text, document)
     return document
 
 
 def get_client_ip(request):
     """
     Return the client IP address from an incoming HTTP request.
 
     Args:
         request (django.http.HttpRequest): the incoming HTTP request
 
     Returns:
         str: The client IP address
     """
     x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
     if x_forwarded_for:
         ip = x_forwarded_for.split(",")[0]
     else:
         ip = request.META.get("REMOTE_ADDR")
     return ip
 
 
 def is_swh_web_development(request: HttpRequest) -> bool:
     """Indicate if we are running a development version of swh-web."""
     site_base_url = request.build_absolute_uri("/")
     return any(
         host in site_base_url for host in ("localhost", "127.0.0.1", "testserver")
     )
 
 
 def is_swh_web_staging(request: HttpRequest) -> bool:
     """Indicate if we are running a staging version of swh-web."""
     config = get_config()
     site_base_url = request.build_absolute_uri("/")
     return any(
         server_name in site_base_url for server_name in config["staging_server_names"]
     )
 
 
 def is_swh_web_production(request: HttpRequest) -> bool:
     """Indicate if we are running the public production version of swh-web."""
     return SWH_WEB_SERVER_NAME in request.build_absolute_uri("/")
 
 
 browsers_supported_image_mimes = set(
     [
         "image/gif",
         "image/png",
         "image/jpeg",
         "image/bmp",
         "image/webp",
         "image/svg",
         "image/svg+xml",
     ]
 )
 
 
 def context_processor(request):
     """
     Django context processor used to inject variables
     in all swh-web templates.
     """
     config = get_config()
     if (
         hasattr(request, "user")
         and request.user.is_authenticated
         and not hasattr(request.user, "backend")
     ):
         # To avoid django.template.base.VariableDoesNotExist errors
         # when rendering templates when standard Django user is logged in.
         request.user.backend = "django.contrib.auth.backends.ModelBackend"
 
     return {
         "swh_object_icons": swh_object_icons,
         "available_languages": None,
         "swh_client_config": config["client_config"],
         "oidc_enabled": bool(config["keycloak"]["server_url"]),
         "browsers_supported_image_mimes": browsers_supported_image_mimes,
         "keycloak": config["keycloak"],
         "site_base_url": request.build_absolute_uri("/"),
         "DJANGO_SETTINGS_MODULE": os.environ["DJANGO_SETTINGS_MODULE"],
         "status": config["status"],
         "swh_web_dev": is_swh_web_development(request),
         "swh_web_staging": is_swh_web_staging(request),
         "swh_web_prod": is_swh_web_production(request),
         "swh_web_version": get_distribution("swh.web").version,
         "iframe_mode": False,
         "ADMIN_LIST_DEPOSIT_PERMISSION": ADMIN_LIST_DEPOSIT_PERMISSION,
         "ADD_FORGE_MODERATOR_PERMISSION": ADD_FORGE_MODERATOR_PERMISSION,
         "FEATURES": get_config()["features"],
         "MAILMAP_ADMIN_PERMISSION": MAILMAP_ADMIN_PERMISSION,
+        "lang": "en",
     }
 
 
 def resolve_branch_alias(
     snapshot: Dict[str, Any], branch: Optional[Dict[str, Any]]
 ) -> Optional[Dict[str, Any]]:
     """
     Resolve branch alias in snapshot content.
 
     Args:
         snapshot: a full snapshot content
         branch: a branch alias contained in the snapshot
     Returns:
         The real snapshot branch that got aliased.
     """
     while branch and branch["target_type"] == "alias":
         if branch["target"] in snapshot["branches"]:
             branch = snapshot["branches"][branch["target"]]
         else:
             from swh.web.common import archive
 
             snp = archive.lookup_snapshot(
                 snapshot["id"], branches_from=branch["target"], branches_count=1
             )
             if snp and branch["target"] in snp["branches"]:
                 branch = snp["branches"][branch["target"]]
             else:
                 branch = None
     return branch
 
 
 class _NoHeaderHTMLTranslator(HTMLTranslator):
     """
     Docutils translator subclass to customize the generation of HTML
     from reST-formatted docstrings
     """
 
     def __init__(self, document):
         super().__init__(document)
         self.body_prefix = []
         self.body_suffix = []
 
 
 _HTML_WRITER = Writer()
 _HTML_WRITER.translator_class = _NoHeaderHTMLTranslator
 
 
 def rst_to_html(rst: str) -> str:
     """
     Convert reStructuredText document into HTML.
 
     Args:
         rst: A string containing a reStructuredText document
 
     Returns:
         Body content of the produced HTML conversion.
 
     """
     settings = {
         "initial_header_level": 2,
         "halt_level": 4,
         "traceback": True,
         "file_insertion_enabled": False,
         "raw_enabled": False,
     }
     pp = publish_parts(rst, writer=_HTML_WRITER, settings_overrides=settings)
     return f'<div class="swh-rst">{pp["html_body"]}</div>'
 
 
 def prettify_html(html: str) -> str:
     """
     Prettify an HTML document.
 
     Args:
         html: Input HTML document
 
     Returns:
         The prettified HTML document
     """
     return BeautifulSoup(html, "lxml").prettify()
 
 
 def django_cache(
     timeout: int = DEFAULT_TIMEOUT,
     catch_exception: bool = False,
     exception_return_value: Any = None,
     invalidate_cache_pred: Callable[[Any], bool] = lambda val: False,
 ):
     """Decorator to put the result of a function call in Django cache,
     subsequent calls will directly return the cached value.
 
     Args:
         timeout: The number of seconds value will be hold in cache
         catch_exception: If :const:`True`, any thrown exception by
             the decorated function will be caught and not reraised
         exception_return_value: The value to return if previous
             parameter is set to :const:`True`
         invalidate_cache_pred: A predicate function enabling to
             invalidate the cache under certain conditions, decorated
             function will then be called again
 
     Returns:
         The returned value of the decorated function for the specified
         parameters
 
     """
 
     def inner(func):
         @functools.wraps(func)
         def wrapper(*args, **kwargs):
             func_args = args + (0,) + tuple(sorted(kwargs.items()))
             cache_key = str(hash((func.__module__, func.__name__) + func_args))
             ret = cache.get(cache_key)
             if ret is None or invalidate_cache_pred(ret):
                 try:
                     ret = func(*args, **kwargs)
                 except Exception as exc:
                     if catch_exception:
                         sentry_capture_exception(exc)
                         return exception_return_value
                     else:
                         raise
                 else:
                     cache.set(cache_key, ret, timeout=timeout)
             return ret
 
         return wrapper
 
     return inner
 
 
 def _deposits_list_url(
     deposits_list_base_url: str, page_size: int, username: Optional[str]
 ) -> str:
     params = {"page_size": str(page_size)}
     if username is not None:
         params["username"] = username
     return f"{deposits_list_base_url}?{urllib.parse.urlencode(params)}"
 
 
 def get_deposits_list(username: Optional[str] = None) -> List[Dict[str, Any]]:
     """Return the list of software deposits using swh-deposit API"""
     config = get_config()["deposit"]
     private_api_url = config["private_api_url"].rstrip("/") + "/"
     deposits_list_base_url = private_api_url + "deposits"
     deposits_list_auth = HTTPBasicAuth(
         config["private_api_user"], config["private_api_password"]
     )
 
     deposits_list_url = _deposits_list_url(
         deposits_list_base_url, page_size=1, username=username
     )
 
     nb_deposits = requests.get(
         deposits_list_url, auth=deposits_list_auth, timeout=30
     ).json()["count"]
 
     @django_cache(invalidate_cache_pred=lambda data: data["count"] != nb_deposits)
     def _get_deposits_data():
         deposits_list_url = _deposits_list_url(
             deposits_list_base_url, page_size=nb_deposits, username=username
         )
         return requests.get(
             deposits_list_url,
             auth=deposits_list_auth,
             timeout=30,
         ).json()
 
     deposits_data = _get_deposits_data()
 
     return deposits_data["results"]
 
 
 _origin_visit_types_cache_timeout = 24 * 60 * 60  # 24 hours
 
 
 @django_cache(
     timeout=_origin_visit_types_cache_timeout,
     catch_exception=True,
     exception_return_value=[],
 )
 def origin_visit_types() -> List[str]:
     """Return the exhaustive list of visit types for origins
     ingested into the archive.
     """
     return sorted(search().visit_types_count().keys())
 
 
 def redirect_to_new_route(request, new_route, permanent=True):
     """Redirect a request to another route with url args and query parameters
     eg: /origin/<url:url-val>/log?path=test can be redirected as
     /log?url=<url-val>&path=test. This can be used to deprecate routes
     """
     request_path = resolve(request.path_info)
     args = {**request_path.kwargs, **request.GET.dict()}
     return redirect(
         reverse(new_route, query_params=args),
         permanent=permanent,
     )
diff --git a/swh/web/misc/urls.py b/swh/web/misc/urls.py
index 493eb057..c9b673f8 100644
--- a/swh/web/misc/urls.py
+++ b/swh/web/misc/urls.py
@@ -1,121 +1,121 @@
 # Copyright (C) 2019-2022  The Software Heritage developers
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU Affero General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
 import json
 
 import requests
 
 from django.conf.urls import include
 from django.contrib.staticfiles import finders
 from django.http import JsonResponse
 from django.shortcuts import render
 from django.urls import re_path as url
 from django.views.decorators.clickjacking import xframe_options_exempt
 
 from swh.web.common import archive
 from swh.web.common.exc import sentry_capture_exception
 from swh.web.config import get_config
 from swh.web.misc.metrics import prometheus_metrics
 
 
 def _jslicenses(request):
     jslicenses_file = finders.find("jssources/jslicenses.json")
     jslicenses_data = json.load(open(jslicenses_file))
     jslicenses_data = sorted(
         jslicenses_data.items(), key=lambda item: item[0].split("/")[-1]
     )
     return render(request, "misc/jslicenses.html", {"jslicenses_data": jslicenses_data})
 
 
 def _stat_counters(request):
     stat_counters = archive.stat_counters()
     url = get_config()["history_counters_url"]
     stat_counters_history = {}
     try:
         response = requests.get(url, timeout=5)
         stat_counters_history = json.loads(response.text)
     except Exception as exc:
         sentry_capture_exception(exc)
 
     counters = {
         "stat_counters": stat_counters,
         "stat_counters_history": stat_counters_history,
     }
     return JsonResponse(counters)
 
 
 @xframe_options_exempt
 def hiring_banner(request):
 
     lang = request.GET.get("lang")
 
     return render(
         request,
-        "misc/hiring-banner.html",
+        "misc/hiring-banner-iframe.html",
         {
             "lang": lang if lang else "en",
         },
     )
 
 
 urlpatterns = [
     url(r"^", include("swh.web.misc.coverage")),
     url(r"^jslicenses/$", _jslicenses, name="jslicenses"),
     url(r"^", include("swh.web.misc.origin_save")),
     url(r"^stat_counters/$", _stat_counters, name="stat-counters"),
     url(r"^", include("swh.web.misc.badges")),
     url(r"^metrics/prometheus/$", prometheus_metrics, name="metrics-prometheus"),
     url(r"^", include("swh.web.misc.iframe")),
     url(r"^", include("swh.web.misc.fundraising")),
     url(r"^hiring/banner/$", hiring_banner, name="swh-hiring-banner"),
 ]
 
 
 # when running end to end tests through cypress, declare some extra
 # endpoints to provide input data for some of those tests
 if get_config()["e2e_tests_mode"]:
     from swh.web.tests.views import (
         get_content_code_data_all_exts,
         get_content_code_data_all_filenames,
         get_content_code_data_by_ext,
         get_content_code_data_by_filename,
         get_content_other_data_by_ext,
     )
 
     urlpatterns.append(
         url(
             r"^tests/data/content/code/extension/(?P<ext>.+)/$",
             get_content_code_data_by_ext,
             name="tests-content-code-extension",
         )
     )
     urlpatterns.append(
         url(
             r"^tests/data/content/other/extension/(?P<ext>.+)/$",
             get_content_other_data_by_ext,
             name="tests-content-other-extension",
         )
     )
     urlpatterns.append(
         url(
             r"^tests/data/content/code/extensions/$",
             get_content_code_data_all_exts,
             name="tests-content-code-extensions",
         )
     )
     urlpatterns.append(
         url(
             r"^tests/data/content/code/filename/(?P<filename>.+)/$",
             get_content_code_data_by_filename,
             name="tests-content-code-filename",
         )
     )
     urlpatterns.append(
         url(
             r"^tests/data/content/code/filenames/$",
             get_content_code_data_all_filenames,
             name="tests-content-code-filenames",
         )
     )
diff --git a/swh/web/templates/layout.html b/swh/web/templates/layout.html
index 1cd6d614..b43f2b1e 100644
--- a/swh/web/templates/layout.html
+++ b/swh/web/templates/layout.html
@@ -1,311 +1,313 @@
 {% comment %}
 Copyright (C) 2015-2022  The Software Heritage developers
 See the AUTHORS file at the top-level directory of this distribution
 License: GNU Affero General Public License version 3, or any later version
 See top-level LICENSE file for more information
 {% endcomment %}
 
 <!DOCTYPE html>
 
 {% load js_reverse %}
 {% load static %}
 {% load render_bundle from webpack_loader %}
 {% load swh_templatetags %}
 
 <html lang="en">
   <head>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <title>{% block title %}{% endblock %}</title>
 
     {% render_bundle 'vendors' %}
     {% render_bundle 'webapp' %}
     {% render_bundle 'guided_tour' %}
 
     <script>
 /*
 @licstart  The following is the entire license notice for the JavaScript code in this page.
 
 Copyright (C) 2015-2022  The Software Heritage developers
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as
 published by the Free Software Foundation, either version 3 of the
 License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.
 
 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 @licend  The above is the entire license notice for the JavaScript code in this page.
 */
     </script>
 
     <script>
       SWH_CONFIG = {{swh_client_config|jsonify}};
       swh.webapp.sentryInit(SWH_CONFIG.sentry_dsn);
     </script>
 
     <script src="{% url 'js_reverse' %}" type="text/javascript"></script>
 
     <script>
       swh.webapp.setSwhObjectIcons({{ swh_object_icons|jsonify }});
     </script>
 
     {{ request.user.is_authenticated|json_script:"swh_user_logged_in" }}
 
     {% include "includes/favicon.html" %}
 
     {% block header %}{% endblock %}
 
     {% if swh_web_prod %}
 
       <!-- Matomo -->
       <script type="text/javascript">
         var _paq = window._paq = window._paq || [];
         _paq.push(['trackPageView']);
         (function() {
           var u="https://piwik.inria.fr/";
           _paq.push(['setTrackerUrl', u+'matomo.php']);
           _paq.push(['setSiteId', '59']);
           var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
           g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
         })();
       </script>
       <!-- End Matomo Code -->
 
     {% endif %}
 
   </head>
 
   <body class="hold-transition layout-fixed sidebar-mini">
     <a id="top"></a>
     <div class="wrapper">
       <div class="swh-top-bar">
         <ul>
           <li class="swh-position-left">
             <div id="swh-full-width-switch-container" class="custom-control custom-switch d-none d-lg-block d-xl-block">
               <input type="checkbox" class="custom-control-input" id="swh-full-width-switch" onclick="swh.webapp.fullWidthToggled(event)">
               <label class="custom-control-label font-weight-normal" for="swh-full-width-switch">Full width</label>
             </div>
           </li>
           <li>
             <a href="https://www.softwareheritage.org">Home</a>
           </li>
           <li>
             <a href="https://forge.softwareheritage.org/">Development</a>
           </li>
           <li>
             <a href="https://docs.softwareheritage.org/devel/">Documentation</a>
           </li>
           <li>
             <a class="swh-donate-link" href="https://www.softwareheritage.org/donate">Donate</a>
           </li>
           <li class="swh-position-right">
             <a href="{{ status.server_url }}" target="_blank"
               class="swh-current-status mr-3 d-none d-lg-inline-block d-xl-inline-block">
               <span id="swh-current-status-description">Operational</span>
               <i class="swh-current-status-indicator green"></i>
             </a>
             {% url 'logout' as logout_url %}
             {% if user.is_authenticated %}
               Logged in as
               {% if 'OIDC' in user.backend %}
                 <a id="swh-login" href="{% url 'oidc-profile' %}"><strong>{{ user.username }}</strong></a>,
                 <a href=  "{% url 'oidc-logout' %}?next_path={% url 'logout' %}?remote_user=1">logout</a>
               {% else %}
                 <strong id="swh-login">{{ user.username }}</strong>,
                 <a href="{{ logout_url }}">logout</a>
               {% endif %}
             {% elif oidc_enabled %}
               {% if request.path != logout_url %}
                 <a id="swh-login" href="{% url 'oidc-login' %}?next_path={{ request.build_absolute_uri }}">login</a>
               {% else %}
                 <a id="swh-login" href="{% url 'oidc-login' %}">login</a>
               {% endif %}
             {% else %}
               {% if request.path != logout_url %}
                 <a id="swh-login" href="{% url 'login' %}?next={{ request.build_absolute_uri }}">login</a>
               {% else %}
                 <a id="swh-login" href="{% url 'login' %}">login</a>
               {% endif %}
             {% endif %}
           </li>
         </ul>
       </div>
-      <iframe class="swh-banner-iframe" src="{% url 'swh-hiring-banner' %}"></iframe>
+      <div class="swh-banner">
+        {% include "misc/hiring-banner.html" %}
+      </div>
       <nav class="main-header navbar navbar-expand-lg navbar-light navbar-static-top" id="swh-navbar">
         <div class="navbar-header">
           <a class="nav-link swh-push-menu" data-widget="pushmenu" data-enable-remember="true" href="#">
             <i class="mdi mdi-24px mdi-menu mdi-fw" aria-hidden="true"></i>
           </a>
         </div>
         <div class="navbar" style="width: 94%;">
           <div class="swh-navbar-content">
             {% block navbar-content %}{% endblock %}
             {% if request.resolver_match.url_name != 'swh-web-homepage' and request.resolver_match.url_name != 'browse-search' %}
               <form class="form-horizontal d-none d-md-flex input-group swh-search-navbar needs-validation"
                   id="swh-origins-search-top">
                 <input class="form-control"
                   placeholder="Enter a SWHID to resolve or keyword(s) to search for in origin URLs"
                   type="text" id="swh-origins-search-top-input"
                   oninput="swh.webapp.validateSWHIDInput(this)" required/>
                 <div class="input-group-append">
                   <button class="btn btn-primary" type="submit">
                   <i class="swh-search-icon mdi mdi-24px mdi-magnify" aria-hidden="true"></i>
                   </button>
                 </div>
               </form>
             {% endif %}
           </div>
         </div>
       </nav>
     </div>
 
     <aside class="swh-sidebar main-sidebar sidebar-no-expand sidebar-light-primary elevation-4">
       <a href="{% url 'swh-web-homepage' %}" class="brand-link">
         <img class="brand-image" src="{% static 'img/swh-logo.png' %}">
         <div class="brand-text sitename" href="{% url 'swh-web-homepage' %}">
           <span class="first-word">Software</span> <span class="second-word">Heritage</span>
         </div>
       </a>
 
       <a href="/" class="swh-words-logo">
         <div class="swh-words-logo-swh">
           <span class="first-word">Software</span>
           <span class="second-word">Heritage</span>
         </div>
         <span>Archive</span>
       </a>
 
       <div class="sidebar">
         <nav class="mt-2">
           <ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
             <li class="nav-header">Features</li>
             <li class="nav-item swh-search-item" title="Search archived software">
               <a href="{% url 'browse-search' %}" class="nav-link swh-search-link">
                 <i style="color: #e20026;" class="nav-icon mdi mdi-24px mdi-magnify"></i>
                 <p>Search</p>
               </a>
             </li>
             <li class="nav-item swh-vault-item" title="Download archived software from the Vault">
               <a href="{% url 'browse-vault' %}" class="nav-link swh-vault-link">
                 <i style="color: #e20026;" class="nav-icon mdi mdi-24px mdi-download"></i>
                 <p>Downloads</p>
               </a>
             </li>
             <li class="nav-item swh-origin-save-item" title="Request the saving of a software origin into the archive">
               <a href="{% url 'origin-save' %}" class="nav-link swh-origin-save-link">
                 <i style="color: #e20026;" class="nav-icon mdi mdi-24px mdi-camera"></i>
                 <p>Save code now</p>
               </a>
             </li>
             {% if FEATURES.add_forge_now %}
             <li class="nav-item swh-origin-save-item" title="Request adding a new forge listing">
               <a href="{% url 'forge-add-create' %}" class="nav-link swh-forge-add-link">
                 <i style="color: #e20026;" class="nav-icon mdi mdi-24px mdi-anvil"></i>
                 <p>Add forge now</p>
               </a>
             </li>
             {% endif %}
             <li class="nav-item swh-help-item" title="How to browse the archive ?">
               <a href="#" class="nav-link swh-help-link" onclick="swh.guided_tour.guidedTourButtonClick(event)">
                 <i style="color: #e20026;" class="nav-icon mdi mdi-24px mdi-help-circle"></i>
                 <p>Help</p>
               </a>
             </li>
             {% if user.is_authenticated %}
               <li class="nav-header">Administration</li>
               {% if user.is_staff %}
                 <li class="nav-item swh-origin-save-admin-item" title="Save code now administration">
                   <a href="{% url 'admin-origin-save-requests' %}" class="nav-link swh-origin-save-admin-link">
                     <i style="color: #fecd1b;" class="nav-icon mdi mdi-24px mdi-camera"></i>
                     <p>Save code now</p>
                   </a>
                 </li>
               {% endif %}
               {% if FEATURES.add_forge_now %}
                 {% if user.is_staff or ADD_FORGE_MODERATOR_PERMISSION in user.get_all_permissions %}
                 <li class="nav-item swh-forge-add-moderation-item" title="Add forge now moderation">
                   <a href="{% url 'add-forge-now-requests-moderation' %}" class="nav-link swh-forge-add-moderation-link">
                     <i style="color: #fecd1b;" class="nav-icon mdi mdi-24px mdi-anvil"></i>
                     <p>Add forge now</p>
                   </a>
                 </li>
                 {% endif %}
               {% endif %}
               {% if user.is_staff or ADMIN_LIST_DEPOSIT_PERMISSION in user.get_all_permissions %}
                 <li class="nav-item swh-deposit-admin-item" title="Deposit administration">
                   <a href="{% url 'admin-deposit' %}" class="nav-link swh-deposit-admin-link">
                     <i style="color: #fecd1b;" class="nav-icon mdi mdi-24px mdi-folder-upload"></i>
                     <p>Deposit</p>
                   </a>
                 </li>
               {% endif %}
               {% if MAILMAP_ADMIN_PERMISSION in user.get_all_permissions %}
                 <li class="nav-item swh-mailmap-admin-item" title="Mailmap administration">
                   <a href="{% url 'admin-mailmap' %}" class="nav-link swh-mailmap-admin-link">
                     <i style="color: #fecd1b;" class="nav-icon mdi mdi-24px mdi-email"></i>
                     <p>Mailmap</p>
                   </a>
                 </li>
               {% endif %}
             {% endif %}
           </ul>
         </nav>
       </div>
     </aside>
 
     <div class="content-wrapper">
       <section class="content">
         <div class="container" id="swh-web-content">
           {% if swh_web_staging %}
             <div class="swh-corner-ribbon">Staging<br/>v{{ swh_web_version }}</div>
           {% elif swh_web_dev %}
             <div class="swh-corner-ribbon">Development<br/>v{{ swh_web_version|split:"+"|first }}</div>
           {% endif %}
           {% block content %}{% endblock %}
         </div>
       </section>
     </div>
 
     {% include "includes/global-modals.html" %}
 
     <footer class="footer">
       <div class="container text-center">
         <a href="https://www.softwareheritage.org">Software Heritage</a> &mdash;
         Copyright (C) 2015&ndash;{% now "Y" %}, The Software Heritage developers.
         License: <a href="https://www.gnu.org/licenses/agpl.html">GNU
         AGPLv3+</a>. <br/> The source code of Software Heritage <em>itself</em>
         is available on
         our <a href="https://forge.softwareheritage.org/">development
         forge</a>. <br/> The source code files <em>archived</em> by Software
         Heritage are available under their own copyright and licenses. <br/>
         <span class="link-color">Terms of use: </span>
         <a href="https://www.softwareheritage.org/legal/bulk-access-terms-of-use/">Archive access</a>,
         <a href="https://www.softwareheritage.org/legal/api-terms-of-use/">API</a>-
         <a href="https://www.softwareheritage.org/contact/">Contact</a>-
         <a href="{% url 'jslicenses' %}" rel="jslicense">JavaScript license information</a>-
         <a href="{% url 'api-1-homepage' %}">Web API</a><br/>
         {% if "production" not in DJANGO_SETTINGS_MODULE  %}
           swh-web v{{ swh_web_version }}
         {% endif %}
       </div>
     </footer>
     <div id="back-to-top">
       <a href="#top"><img alt="back to top" src="{% static 'img/arrow-up-small.png' %}" /></a>
     </div>
     <script>
       swh.webapp.setContainerFullWidth();
       var statusServerURL = {{ status.server_url|jsonify }};
       var statusJsonPath = {{ status.json_path|jsonify }};
       swh.webapp.initStatusWidget(statusServerURL + statusJsonPath);
     </script>
   </body>
 
 </html>
diff --git a/swh/web/templates/misc/hiring-banner.html b/swh/web/templates/misc/hiring-banner-iframe.html
similarity index 65%
copy from swh/web/templates/misc/hiring-banner.html
copy to swh/web/templates/misc/hiring-banner-iframe.html
index 733d8d07..731c4ccc 100644
--- a/swh/web/templates/misc/hiring-banner.html
+++ b/swh/web/templates/misc/hiring-banner-iframe.html
@@ -1,74 +1,54 @@
 {% comment %}
 Copyright (C) 2022  The Software Heritage developers
 See the AUTHORS file at the top-level directory of this distribution
 License: GNU Affero General Public License version 3, or any later version
 See top-level LICENSE file for more information
 {% endcomment %}
 
 <!DOCTYPE html>
 
 {% load static %}
 {% load render_bundle from webpack_loader %}
 
 <html class="swh-banner" lang="en">
   <head>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <title>Software Heritage fundraising banner</title>
     {% render_bundle 'vendors' %}
     <script>
 /*
 @licstart  The following is the entire license notice for the JavaScript code in this page.
 
 Copyright (C) 2022  The Software Heritage developers
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as
 published by the Free Software Foundation, either version 3 of the
 License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.
 
 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 @licend  The above is the entire license notice for the JavaScript code in this page.
 */
     </script>
     <style>
       .swh-banner .row {
           height: 30px;
           background-color: #fecd1b;
           color: #e20026;
           font-size: larger;
       }
     </style>
   </head>
   <body>
-    <div class="content">
-      <div class="container-fluid">
-        <div class="row align-items-center justify-content-end">
-          <div class="col-12 text-center align-middle pr-3">
-            {% if lang == "en" %}
-              We are hiring ! See our
-              <a target="_blank" rel="noopener noreferrer"
-                 href="https://www.softwareheritage.org/jobs/">job offers</a>.
-            {% elif lang == "fr" %}
-              Nous recrutons ! Voir nos
-              <a target="_blank" rel="noopener noreferrer"
-                 href="https://www.softwareheritage.org/jobs/?lang=fr">offres d'emploi</a>.
-            {% elif lang == "es" %}
-              ¡Estamos contratando! Consulta nuestras
-              <a target="_blank" rel="noopener noreferrer"
-                 href="https://www.softwareheritage.org/jobs/?lang=es">ofertas de empleo</a>.
-            {% endif %}
-          </div>
-        </div>
-      </div>
-    </div>
+    {% include "./hiring-banner.html" %}
   </body>
 </html>
diff --git a/swh/web/templates/misc/hiring-banner.html b/swh/web/templates/misc/hiring-banner.html
index 733d8d07..d2aa0863 100644
--- a/swh/web/templates/misc/hiring-banner.html
+++ b/swh/web/templates/misc/hiring-banner.html
@@ -1,74 +1,21 @@
-{% comment %}
-Copyright (C) 2022  The Software Heritage developers
-See the AUTHORS file at the top-level directory of this distribution
-License: GNU Affero General Public License version 3, or any later version
-See top-level LICENSE file for more information
-{% endcomment %}
-
-<!DOCTYPE html>
-
-{% load static %}
-{% load render_bundle from webpack_loader %}
-
-<html class="swh-banner" lang="en">
-  <head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-    <title>Software Heritage fundraising banner</title>
-    {% render_bundle 'vendors' %}
-    <script>
-/*
-@licstart  The following is the entire license notice for the JavaScript code in this page.
-
-Copyright (C) 2022  The Software Heritage developers
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-@licend  The above is the entire license notice for the JavaScript code in this page.
-*/
-    </script>
-    <style>
-      .swh-banner .row {
-          height: 30px;
-          background-color: #fecd1b;
-          color: #e20026;
-          font-size: larger;
-      }
-    </style>
-  </head>
-  <body>
-    <div class="content">
-      <div class="container-fluid">
-        <div class="row align-items-center justify-content-end">
-          <div class="col-12 text-center align-middle pr-3">
-            {% if lang == "en" %}
-              We are hiring ! See our
-              <a target="_blank" rel="noopener noreferrer"
-                 href="https://www.softwareheritage.org/jobs/">job offers</a>.
-            {% elif lang == "fr" %}
-              Nous recrutons ! Voir nos
-              <a target="_blank" rel="noopener noreferrer"
-                 href="https://www.softwareheritage.org/jobs/?lang=fr">offres d'emploi</a>.
-            {% elif lang == "es" %}
-              ¡Estamos contratando! Consulta nuestras
-              <a target="_blank" rel="noopener noreferrer"
-                 href="https://www.softwareheritage.org/jobs/?lang=es">ofertas de empleo</a>.
-            {% endif %}
-          </div>
-        </div>
+<div class="content">
+  <div class="container-fluid">
+    <div class="row align-items-center justify-content-end">
+      <div class="col-12 text-center align-middle pr-3">
+        {% if lang == "en" %}
+          We are hiring ! See our
+          <a target="_blank" rel="noopener noreferrer"
+              href="https://www.softwareheritage.org/jobs/">job offers</a>.
+        {% elif lang == "fr" %}
+          Nous recrutons ! Voir nos
+          <a target="_blank" rel="noopener noreferrer"
+              href="https://www.softwareheritage.org/jobs/?lang=fr">offres d'emploi</a>.
+        {% elif lang == "es" %}
+          ¡Estamos contratando! Consulta nuestras
+          <a target="_blank" rel="noopener noreferrer"
+              href="https://www.softwareheritage.org/jobs/?lang=es">ofertas de empleo</a>.
+        {% endif %}
       </div>
     </div>
-  </body>
-</html>
+  </div>
+</div>
\ No newline at end of file